package cn.edu.zut.soft.graduate.userCenter.bo;

import cn.edu.zut.soft.basic.core.model.bo.CommonResult;
import cn.edu.zut.soft.basic.core.model.dao.Example;
import cn.edu.zut.soft.graduate.base.excel.ExcelFileHandler;
import cn.edu.zut.soft.graduate.base.excel.ExcelHandlerFactory;
import cn.edu.zut.soft.graduate.base.excel.Excetion.HandleException;
import cn.edu.zut.soft.graduate.base.excel.handle.Handle;
import cn.edu.zut.soft.graduate.base.former.IdTransformer;
import cn.edu.zut.soft.graduate.base.former.InfoIdentityTransformer;
import cn.edu.zut.soft.graduate.base.former.InfoValueTransformer;
import cn.edu.zut.soft.graduate.base.former.StringToIntegerTransformer;
import cn.edu.zut.soft.graduate.core.constant.Address;
import cn.edu.zut.soft.graduate.core.constant.InfoType;
import cn.edu.zut.soft.graduate.core.constant.IssueSource;
import cn.edu.zut.soft.graduate.core.constant.Role;
import cn.edu.zut.soft.graduate.core.constant.config.IKEY;
import cn.edu.zut.soft.graduate.core.design.BasicInfoStrategy;
import cn.edu.zut.soft.graduate.core.design.InfoStrategy;
import cn.edu.zut.soft.graduate.core.model.Impl.CreateGroup;
import cn.edu.zut.soft.graduate.core.model.Impl.Group;
import cn.edu.zut.soft.graduate.core.model.Impl.Identity;
import cn.edu.zut.soft.graduate.core.model.Impl.Info;
import cn.edu.zut.soft.graduate.core.model.view.TeacherGroupVO;
import cn.edu.zut.soft.graduate.core.query.IdentityQuery;
import cn.edu.zut.soft.graduate.core.query.InfoQuery;
import cn.edu.zut.soft.graduate.core.vo.LoginVO;
import cn.edu.zut.soft.graduate.core.vo.UserDescVO;
import cn.edu.zut.soft.graduate.fileUploadCenter.bo.FileUploadBO;
import cn.edu.zut.soft.graduate.groupCenter.bo.GroupBO;
import cn.edu.zut.soft.graduate.groupCenter.bo.TeacherGroupBO;
import cn.edu.zut.soft.graduate.userCenter.dao.InfoDAO;
import com.alibaba.fastjson.JSON;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;


/**
 * Created by chuchuang on 16/11/14.
 */
@Data
@Slf4j
public class StudentBOImpl implements StudentBO {

    private ExcelFileHandler excelFileHandler;

    private List<Handle> excelOPList;

    @Resource
    private InfoIdentityTransformer infoIdentityTransformer;

    @Resource
    private IdTransformer idTransformer;

    @Resource
    private InfoValueTransformer infoValueTransformer;

    @Resource
    private StringToIntegerTransformer stringToIntegerTransformer;

    @Resource
    private IdentityBO identityBO;

    @Resource
    private ExcelHandlerFactory excelHandlerFactory;

    @Resource
    private FileUploadBO fileUploadBO;

    @Resource
    private InfoBO infoBO;

    @Resource
    private GroupBO groupBO;

    @Resource
    private TeacherGroupBO teacherGroupBO;

    @Resource
    private TeacherBO teacherBO;

    @Value("#{commonProp['ignoreIds']}")
    private String ignoreIds;

    @Resource
    private InfoDAO infoDAO;

    @Override
    @Transactional
    public String uploadStudent(InputStream inputStream, String fileName, long fileSize, LoginVO loginVO) {
        String url = null;
        try {
            url = fileUploadBO.upload(inputStream, fileName, fileSize, loginVO);
        } catch (Exception e) {
            log.error("fileupload is error", e);
            throw HandleException.create("fileupload is error", e);
        }
        List<Map<String, String>> mapList = null;
        try {
            mapList = excelHandlerFactory.analysis(url, excelFileHandler);
        } catch (IOException e) {
            log.error("url file is error", e);
            throw HandleException.create("url file is error", e);
        }
        for (Handle handle : excelOPList) {
            handle.Handle(mapList);
        }
        return url;
    }


    @Override
    public List<UserDescVO> noGroupInstantiate(LoginVO loginVO) {
        Assert.notNull(loginVO);
        InfoQuery infoQuery = new InfoQuery();
        //清除分页
        infoQuery.clear();
        infoQuery.setInfoType(InfoType.Group);
        infoQuery.setKey(IKEY.GROUP);
        infoQuery.setRole(Role.stu);
        List<Info> infoList = infoBO.findByQuery(infoQuery).getData();
        List<Integer> ids = new ArrayList<>(infoList.size());
        if (!infoList.isEmpty()) {
            //获取所有小组的用户集合
            CollectionUtils.collect(infoList, new Transformer() {
                @Override
                public Object transform(Object o) {
                    return ((Info) o).getIdentityId();
                }
            }, ids);

        } else {
            log.warn("不存在任何学生小组");
            //设置默认0,这个为不可能存在的数据
            ids.add(0);
        }
        IdentityQuery identityQuery = new IdentityQuery();
        identityQuery.clear();
        identityQuery.setNotIds(ids);
        identityQuery.setRole(Role.stu);
        List<Identity> identityList = identityBO.findByQuery(identityQuery).getData();
        //如果结果不存在则返回
        if (CollectionUtils.isEmpty(identityList)){
            return Collections.emptyList();
        }
        //对学生进行循环建组
        CreateGroup createGroup;
        Group group;
        for (Identity identity: identityList){
            group = new Group();
            group.setRole(identity.getRole());
            group.setIdentityId(identity.getId());
            group.setIdentityName(identity.getName());
            group.setCount(1);
            group.setStatus(IssueSource.school);
            //创建私人小组
            groupBO.save(group,loginVO.getName());
            //关联小组
            infoBO.save(new BasicInfoStrategy(InfoType.Group,IKEY.GROUP,group.getId().toString()),identity.getId(),loginVO.getName());
            //设定组长
            infoBO.save(new BasicInfoStrategy(InfoType.Group,IKEY.GroupLeader,group.getId().toString()),identity.getId(),loginVO.getName());
            //做出标记
            infoBO.save(new BasicInfoStrategy(InfoType.Positive,IKEY.UnEnergetic,group.getId().toString()),identity.getId(),loginVO.getName());
        }
        //清空
        ids.clear();
        CollectionUtils.collect(identityList, new Transformer() {
            @Override
            public Integer transform(Object o) {
                return ((Identity)o).getId();
            }
        },ids);
        identityQuery = new IdentityQuery();
        identityQuery.clear();
        identityQuery.setIds(ids);
        identityQuery.setRole(Role.stu);
        return identityBO.userPersonal(identityQuery,IKEY.StuInfoAll);
    }

    @Override
    public CommonResult assignStuGrouop(LoginVO loginVO, Integer teaId, Integer groupId) {
        Assert.notNull(loginVO);
        Assert.notNull(teaId);
        Assert.notNull(groupId);
        InfoQuery infoQuery = new InfoQuery();
        infoQuery.setInfoType(InfoType.Group);
        infoQuery.setKey(IKEY.GROUP);
        infoQuery.setValue(groupId.toString());
        List<Info> infoList = infoBO.findByQuery(infoQuery).getData();
        Identity identity = identityBO.get(teaId);
        Assert.notNull(identity,"教师不存在");
        for (Info info:infoList){
            infoBO.save(new BasicInfoStrategy(InfoType.Tea, IKEY.Guide, identity.getId().toString()), info.getIdentityId(), loginVO.getName());
            infoBO.save(new BasicInfoStrategy(InfoType.Tea, IKEY.GuideName, identity.getName()), info.getIdentityId(), loginVO.getName());
        }
        return CommonResult.successReturn(infoList) ;
    }

    /**
     * 检索教师小组下对应的学生列表
     *
     * @param loginVO
     * @param identityQuery
     */
    @Override
    public CommonResult queryStuAllByTeaGroupAndAddress(LoginVO loginVO, IdentityQuery identityQuery) {
        List<Info> infoList = infoBO.queryByUser(loginVO.getId());
        Info groupInfo = null;
        for (Info info: infoList){
            if (InfoType.Group.name().equals(info.getType()) && info.getKey().equals(IKEY.GROUP)){
                groupInfo = info;
            }
        }
        if (groupInfo == null){
            return CommonResult.errorReturn("小组信息不存在");
        }
        identityQuery.setGroupId(Integer.parseInt(groupInfo.getValue()));
        return CommonResult.successReturn(queryStuAllByTeaGroupAndAddress(identityQuery),identityQuery.getCount().intValue());
    }

    /**
     * 根据教师小组和地址检索
     * @param identityQuery
     * @return
     */
    @Override
    public List<UserDescVO> queryStuAllByTeaGroupAndAddress(IdentityQuery identityQuery){
        InfoQuery infoQuery = new InfoQuery();
        infoQuery.clear();
        //查询的是学生
        infoQuery.setRole(Role.stu);
        if (identityQuery.getGroupId() != null) {
            //chuchuang 添加小组反向查询
            //判断是否反转
            if (identityQuery.isReverse()){
                //检测是否是教师小组
                TeacherGroupVO teacherGroupVO = teacherGroupBO.get(identityQuery.getGroupId());
                if (teacherGroupVO != null){
                    //没有对接，返回空集合
                    if (teacherGroupVO.getParallelism() == null){
                        return Collections.emptyList();
                    }
                    //对接成功,反转小组id
                    identityQuery.setGroupId(teacherGroupVO.getParallelism().getId());
                }
            }
            List<Info> teaList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Group, IKEY.GROUP, identityQuery.getGroupId().toString())));
            if (CollectionUtils.isEmpty(teaList)) {
                return Collections.emptyList();
            }
            Set<String> teaIds = new HashSet<>(teaList.size());
            CollectionUtils.collect(teaList, infoIdentityTransformer, teaIds);
            infoQuery.setInfoType(InfoType.Tea);
            infoQuery.setKey(IKEY.Guide);
            infoQuery.setValueList(new ArrayList<String>(teaIds));
        }
        List<Info> stuList = infoBO.findByQuery(infoQuery).getData();
        Set<Integer> stuIds = new HashSet<Integer>(stuList.size());
        CollectionUtils.collect(stuList,infoIdentityTransformer,stuIds);
        CollectionUtils.collect(stuIds,stringToIntegerTransformer);
        //当存在地址时做数据转换
        stuIds = transfromerofaddress(identityQuery, stuIds);
        //当不存在时,返回null
        if (CollectionUtils.isEmpty(stuIds)){
            return Collections.emptyList();
        }
        identityQuery.setIds(new ArrayList<Integer>(stuIds));
//        identityQuery.clear();
        return identityBO.userPersonal(identityQuery,IKEY.StuInfoAll);
    }

    @Override
    public List<UserDescVO> queryStuAllBySystemGrade(IdentityQuery query, String key) {

        InfoQuery infoQuery = new InfoQuery();
        infoQuery.clear();
        infoQuery.setRole(Role.stu);
        if (query.getGroupId() != null){
            //查询该小组下的教师
            List<Info> teaList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Group, IKEY.GROUP, query.getGroupId().toString())));
            if (CollectionUtils.isEmpty(teaList)) {
                return Collections.emptyList();
            }
            Set<String> teaIds = new HashSet<>(teaList.size());
            CollectionUtils.collect(teaList, infoIdentityTransformer, teaIds);
            infoQuery.setInfoType(InfoType.Tea);
            infoQuery.setKey(IKEY.Guide);
            infoQuery.setValueList(new ArrayList<String>(teaIds));
        }
        //该教师小组下的所有学生
        List<Info> stuList = infoBO.findByQuery(infoQuery).getData();
        Set<Integer> stuIds = new HashSet<Integer>(stuList.size());
        CollectionUtils.collect(stuList,infoIdentityTransformer,stuIds);
        CollectionUtils.collect(stuIds,stringToIntegerTransformer);
        stuIds = getGradeStatus(key, stuIds);
        //当不存在时,返回null
        if (CollectionUtils.isEmpty(stuIds)){
            return Collections.emptyList();
        }
        query.setIds(new ArrayList<Integer>(stuIds));
        return identityBO.userPersonal(query,IKEY.StuInfoAll);
    }

    /**
     * 同步用户开题地址
     */
    @Override
    public void syncAddress(LoginVO loginVO) {
        //默认郑州地区
        Address address = Address.zhengzhou;
        IdentityQuery identityQuery = new IdentityQuery();
        identityQuery.clear();
        identityQuery.setRole(Role.stu);
        List<Identity> identityList = identityBO.findByQuery(identityQuery).getData();
        //存在的学生
        List<Info> infoList = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Basic,IKEY.ADDRESS,null)));
        Set<Integer> ids = new HashSet<>();
        CollectionUtils.collect(infoList,infoIdentityTransformer,ids);
        int count = 0;
        for (Identity identity : identityList){
            if (!ids.contains(identity.getId())){
                infoBO.save(new BasicInfoStrategy(InfoType.Basic,IKEY.ADDRESS,address.name()),identity.getId(),loginVO.getName());
                count++;
            }
        }
        log.warn("syncAddress count = {}",count);
    }


    //获取地址的学生
    private Set<Integer> transfromerofaddress(IdentityQuery identityQuery, Set<Integer> stuIds) {
        if (identityQuery.getAddress() != null){
            List<Info> addressInfo = infoBO.queryByInfoStrategy(Collections.<InfoStrategy>singletonList(new BasicInfoStrategy(InfoType.Basic, IKEY.ADDRESS,identityQuery.getAddress().name())));
            //数据转换,当学生符合地区的时候摘出来。
            Set<Integer> ids = new HashSet<>(stuIds.size());
            for (Info info : addressInfo){
                if (stuIds.contains(info.getIdentityId())){
                    ids.add(info.getIdentityId());
                }
            }
            stuIds = ids;
        }
        return stuIds;
    }

    /**
     * 随机抽取规则一，雨露均沾
     * @param num 抽取的数目
     * @return 抽取之后的结果
     */
    @Override
    public CommonResult<List<UserDescVO>> randomDrawing(int num){
        IdentityQuery query = new IdentityQuery();
        query.clear();
        CommonResult<Map<Integer, List<Info>>> result = teacherBO.queryExistStudentOfTea(query);
        if (result.getTotalCount() == 0){
            return CommonResult.successReturn(Collections.<UserDescVO>emptyList());
        }
        Map<Integer, List<Info>> map = result.getData();
        List<UserDescVO> all = new ArrayList<>(num);
        Set<Integer> ignore = new HashSet<>();
        List<Integer> ignoreIdsSet = JSON.parseArray(ignoreIds,Integer.class);
        if (!ignoreIdsSet.isEmpty()) {
            ignore.addAll(ignoreIdsSet);
        }
        if (num >= map.size()){
            //风险，每个教师只能保证一个学生
            all.addAll(extract(ignore,map,-1));
            all.addAll(extract(ignore,map,num-map.size()));
        }else {
            all.addAll(extract(ignore,map,num));
        }
        return CommonResult.successReturn(all);
    }

    private List<UserDescVO> extract(Set<Integer> set, Map<Integer, List<Info>> map, int num) {
        if (num == 0) {
            return Collections.emptyList();
        }
        //如果传入为负数，则抽取全部
        List<UserDescVO> identities = new ArrayList<>();
        if (num < 0) {
            log.info("开始全局的人员抽取");
            Random random = new Random();
            for (Map.Entry<Integer, List<Info>> me : map.entrySet()) {
                int rank = 0;
                List<Info> infoList = me.getValue();
                log.info("抽取教师 {} 的学生=>{}", me.getKey(), infoList);
                if (infoList.isEmpty()) {
                    log.info("教师不存在学生,跳过");
                    continue;
                }
                rank = random.nextInt(infoList.size() - 1);
                log.info("随机范围=>{},随机因子=>{}", infoList.size(), rank);
                while (infoList.size() > 1 && set.contains(infoList.get(rank).getIdentityId())) {
                    rank = random.nextInt(infoList.size() - 1);
                }
                Info info = infoList.get(rank);
                set.add(info.getIdentityId());
                identities.add(identityBO.getUserDesc(info.getIdentityId()));
            }
        } else {
            log.info("开始抽取随机的人员");
            Set<Integer> all = new HashSet<>();
            for (Map.Entry<Integer, List<Info>> me : map.entrySet()) {
                for (Info info : me.getValue()) {
                    all.add(info.getIdentityId());
                }
            }
            all.removeAll(set);
            Random random = new Random();
            Set<Integer> ranks = new HashSet<>();
            while (ranks.size() < num){
                ranks.add(random.nextInt(all.size()));
            }
            log.info("随机范围及顺序=>{},随机因子=>{}",all,ranks);
            List<Integer> idsList = new ArrayList<>(all);
            for (Integer rank : ranks){
                identities.add(identityBO.getUserDesc(idsList.get(rank)));
            }

        }
        return identities;
    }

    /**
     * <p>功能描述：根据key查询所需要的学生ID</p>
     * <p>创建人：yangxiaotian</p>
     * <p>创建日期：2017-06-06 23:05:32</p>
     *
     * @param key
     * @param stuIds
     * @return
     */
    private Set<Integer> getGradeStatus(String key,  Set<Integer> stuIds ){
        Example noPass = new Example();
        noPass.createCriteria().andEqualTo("`key`", IKEY.GRADE_STOP_KEY).andEqualTo("del", "0");
        List<Info> stopList = infoDAO.selectByExample(noPass);
        if (StringUtils.isNotBlank(key)){
            Example gradeExample = new Example();
            switch (key){
                case IKEY.EXCELLENCE_GRADE:
                    gradeExample.createCriteria().andEqualTo("`key`", IKEY.FINAL_REPLY_GRADE).andEqualTo("del", "0").andGreaterThanOrEqualTo("`value`", 90);
                    break;
                case IKEY.WELL_GRADE:
                    gradeExample.createCriteria().andEqualTo("`key`", IKEY.FINAL_REPLY_GRADE).andEqualTo("del", "0").andGreaterThanOrEqualTo("`value`", 80).andLessThan("`value`", 90);
                    break;
                case IKEY.PASS_GRADE:
                    gradeExample.createCriteria().andEqualTo("`key`", IKEY.FINAL_REPLY_GRADE).andEqualTo("del", "0").andGreaterThanOrEqualTo("`value`", "60").andLessThan("`value`", 80);
                    break;
                case IKEY.NO_PASS_GRADE:
                    gradeExample.createCriteria().andEqualTo("`key`", IKEY.FINAL_REPLY_GRADE).andEqualTo("del", "0").andLessThan("`value`", 60);
                    break;
                default:
                    gradeExample.createCriteria().andEqualTo("`key`", key).andEqualTo("del","0");
            }
            List<Info> statusInfo = infoDAO.selectByExample(gradeExample);
            if(key.equals(IKEY.NO_PASS_GRADE)){
                statusInfo.addAll(stopList);
            }else{
                if (!CollectionUtils.isEmpty(stopList)){
                    for (Info info: stopList){
                        statusInfo.remove(info);
                    }
                }
            }
            Set<Integer> ids = new HashSet<>(stuIds.size());
            for (Info info : statusInfo){
                if (stuIds.contains(info.getIdentityId())){
                    ids.add(info.getIdentityId());
                }
            }
            stuIds = ids;
        }
//        else{
//            for (Info info : stopList){
//                if (stuIds.contains(info.getIdentityId())){
//                    stuIds.remove(info.getIdentityId());
//                }
//            }
//        }
        return stuIds;
    }

}
